﻿using System;
using CalcSharp.Core.Containers;
using dnAnalytics.Math;

namespace CalcSharp.Core
{
    #region Register structure
    /*
  Register structure:
  * bit     dec. value         meaning
  * ----------------------------------
  * 000       1              number          
  * 001       2              complex         
  * 002       4              set         types
  * 003       8              matrix          
  * 004      16              string          
  * ----------------------------------------------------------
  * 005      32              zero        comon flag ->
  *                                      num = 0
  *                                      |complex| = 0
  *                                      set length = 0
  *                                      mtrx = 1x1 with 0
  *                                      string length =0
  * ----------------------------------------------------------
  * 006      64             nan             
  * 007     128             infinity        
  * 008     256             sign                floating point
  * 009     512             parity          
  * 010    1024             integer
  * ----------------------------------
  * 011    2048             real zero
  * 012    4096             imaginary zero
  * 013    8192             angle 90 degrees    complex numbers
  * 014   16384             angle 0 gegrees
  * ----------------------------------------------------------
  * 015   32768             upercase            string types
  * 016   65536             lowercase
  */
    #endregion
    public enum FlagBit: short
    {
        TNumber = 0,
        TComplex = 1,
        TSet = 2,
        TMatrix = 3,
        TString = 4,
        Zero = 5,
        NaN = 6,
        Infinity = 7,
        Sign = 8,
        Parity = 9,
        Integer = 10,
        Rzero = 11,
        Izero = 12,
        A90 = 13,
        A0 = 14
    }

    public class FlagRegister
    {
        private int RawValue;

        public int ToInt32()
        {
            return this.RawValue;
        }

        public bool this[int bit]
        {
            get
            {
                if (bit < 0 || bit > 31) throw new IndexOutOfRangeException();
                int mask = (1 << bit);
                int res = this.RawValue & mask;
                res = res >> (bit - 1);
                return bit > 0 ? true : false;
            }
            set
            {
                int mask = (1 << bit);
                if (value == true) this.RawValue += mask;
                else this.RawValue -= mask;
            }
        }

        public bool this[FlagBit b]
        {
            get { return this[(int)b]; }
            set { this[(int)b] = value; }
        }

        public void SetRegister(double num)
        {
            this.RawValue = 1; //bit 0
            if (num == 0) this.RawValue += 32; //bit 5
            if (num == double.NaN) this.RawValue += 64; //bit 6
            if (num == double.PositiveInfinity || num == double.NegativeInfinity) this.RawValue += 128; //bit 7
            if (num < 0 || num == double.NegativeInfinity) this.RawValue += 256; //bit 8;
            if (num % 2 == 0) this.RawValue += 512; //bit 9
            if ((num - Math.Truncate(num)) != 0) this.RawValue += 1024;
        }

        public void SetRegister(Complex n)
        {
            this.RawValue = 2; //bit 1
            if (n.Real == 0) this.RawValue += 2048; //bit 11
            if (n.Imaginary == 0) this.RawValue += 4096; //bit 12
            if (n.Imaginary == 0 && n.Real == 0) this.RawValue += 32; //bit 5
            double angle = Math.Atan(n.Imaginary / n.Real);
            if (angle == Math.PI / 2) this.RawValue += 8192; //bit 13
            if (angle == 0) this.RawValue = 16384; //bit 14
        }

        public void SetRegister(ASet s)
        {
            this.RawValue = 4; //bit 2
            if (s.Count == 0) this.RawValue += 32; //bit 5
        }

        public void SetRegister(AMatrix m)
        {
            this.RawValue = 8; //bit 3
            if (m.Rows == 1 && m.Columns == 1 && m[0, 0] == 0) this.RawValue += 32; //bit 5
        }

        public void SetRegister(string s)
        {
            this.RawValue = 16;//bit 4
            if (s == s.ToUpper()) this.RawValue += 32768; //bit 15
            if (s == s.ToLower()) this.RawValue += 65536; //bit 16
        }

        public FlagRegister()
        {
            this.RawValue = 0;
        }
    }
}
